/** 数据库缓存，缓存最近打开的数据库（针对登录用户）
 * @file dbcache.hpp
 * @author Kiven Lee
 * @version 1.0
 * @date 2022-03-29
 *
 * @copyright Kivensoft (c) 2018 - 2022
 *
 */

#ifndef _AI_CACHE_HPP_
#define _AI_CACHE_HPP_

#include <cstdint>
#include <ctime>
#include <memory>
#include <string>
#include <string_view>
#include <list>

#include "aidb.hpp"

namespace ai {

    struct cache_item_t {
        std::string user;           // 用户名，作为查找的主键
        std::string pass;           // 数据库过期后重新打开，需要该项
        std::string token;          // jwt token缓存 （缓存token是为了避免每次都要计算签名）
        time_t      expire;         // 过期时间

        time_t      db_expire;      // 数据库关联缓存（缓存数据库避免每次查询都要重新打开）
        std::unique_ptr<aidb_t> db;

    };

    class db_cache_t {

    public:
        db_cache_t(): _expire_time{}, _db_expire_time{} {}

        ~db_cache_t() { for (auto v : _items) delete v; }

        time_t expire_time() const noexcept { return _expire_time; }
        time_t db_expire_time() const noexcept { return _db_expire_time; }

        void expire_time(uint32_t exp) { _expire_time = exp; }
        void db_expire_time(uint32_t exp) { _db_expire_time = exp; }

        void put(std::unique_ptr<cache_item_t>&& item) { _put(item.release()); }

        void put(const std::string& user, const std::string& pass, const std::string& token,
                std::unique_ptr<aidb_t>&& db) {
            time_t now = std::time(nullptr);
            _put(new cache_item_t{
                .user = user,
                .pass = pass,
                .token = token,
                .expire = _expire_time ? now + _expire_time : 0,
                .db_expire = _db_expire_time ? now + _db_expire_time : 0,
                .db = std::move(db)});
        }

        cache_item_t* get(const std::string_view& user);
        cache_item_t* get_by_token(const std::string_view& token);

        void gc();

    protected:
        std::list<cache_item_t*> _items;
        uint32_t _expire_time;
        uint32_t _db_expire_time;

        void _put(cache_item_t* item);

    };

} // namespace ai

#endif